#pragma once

#include "Socket.hpp"
#include "Protocol.hpp"
#include <functional>

class TcpServer;
class ThreadData
{
public:
    ThreadData(int sock, const std::string &ip, const uint16_t &port, TcpServer *ptr)
        : sock_(sock), clientip_(ip), clientPort_(port), current_(ptr)
    {
    }

public:
    int sock_;
    std::string clientip_;
    uint16_t clientPort_;
    TcpServer *current_;
};
using func_t = std::function<void(yui::Request&,yui::Reaponse*)>;
class TcpServer
{
private:
    static void *threadRoutine(void *args)
    {
        pthread_detach(pthread_self());

        ThreadData *td = static_cast<ThreadData *>(args);
        td->current_->ServiceIO(td->sock_, td->clientip_, td->clientPort_);
        delete td;
        return nullptr;
    }

    void ServiceIO(const int &sock, const std::string ip, const uint16_t &port_)
    {
        std::string inBuff;
        while (true)
        {
            // 1.读取数据
            std::string package;
            int len = yui::ReadPackage(sock,inBuff,&package);
            if(len<0)
                break;
            else if(len == 0)
            {
                //LOG(DEBUG,"user quit->[ip:%s port:%d]",ip.c_str(),port_);
                continue;
            }
            //2.移除报头
            yui::RemoveHeader(package,len);
            // 3.反序列化
            yui::Request req;
            if (req.Deserialization(package) == false)
            {
                LOG(WARNING, "Deserialization fail!");
                continue;
            }
            //4.业务处理
            yui::Reaponse resp;
            func_(req,&resp);
            //5.序列化
            std::string sendMsg;
            resp.Serialization(&sendMsg);
            std::cout<<sendMsg<<std::endl;
            //6.添加报头
            yui::AddHeader(sendMsg);
            //7.发送数据
            send(sock,sendMsg.c_str(),sendMsg.size(),0);
        }
    }

public:
    TcpServer(func_t func,const uint16_t port = defaultPort)
        : func_(func),port_(defaultPort)
    {
    }
    ~TcpServer()
    {
        listenSock_.Close();
    }
    void Init()
    {
        listenSock_.createSocket();
        listenSock_.Bind(port_);
        listenSock_.Listen();
    }
    void Start()
    {
        while (true)
        {
            std::string ip;
            uint16_t port;

            int sock = listenSock_.Accept(&ip, &port);
            if (sock == -1)
            {
                continue;
            }
            pthread_t tid;
            ThreadData *td = new ThreadData(sock, ip, port, this);
            pthread_create(&tid, nullptr, threadRoutine, td);
        }
    }

private:
    yui::Socket listenSock_;
    uint16_t port_;
    func_t func_;
};